在这个项目中,您将使用生成的对抗网络来生成新的面孔图像。
您将在此项目中使用两个数据集:
由于celebA数据集很复杂,而且您首次在项目中执行GAN,我们希望您在CelebA之前测试MNIST上的神经网络。 在MNIST上运行GAN可以让您了解您的模型如何更快地训练。
如果您使用[FloydHub](https://www.floydhub.com/ ),将“data_dir”设置为“/ input”,并使用[FloydHub数据ID](http://docs.floydhub.com/home/using_datasets/ )“R5KrjnANiKVhLWAkpXhNBe”。
data_dir = './data'
# FloydHub - Use with data ID "R5KrjnANiKVhLWAkpXhNBe"
#data_dir = '/input'
"""
DON'T MODIFY ANYTHING IN THIS CELL
"""
import helper
#下载样本数据
helper.download_extract('mnist', data_dir)
helper.download_extract('celeba', data_dir)
如您所知,[MNIST](http://yann.lecun.com/exdb/mnist/ )数据集包含手写数字的图像。 您可以通过更改“show_n_images”来查看第一个示例数。
show_n_images = 25
"""
DON'T MODIFY ANYTHING IN THIS CELL
"""
%matplotlib inline
import os
from glob import glob
from matplotlib import pyplot
mnist_images = helper.get_batch(glob(os.path.join(data_dir, 'mnist/*.jpg'))[:show_n_images], 28, 28, 'L')
pyplot.imshow(helper.images_square_grid(mnist_images, 'L'), cmap='gray')
[CelebFaces属性数据集(CelebA)](http://mmlab.ie.cuhk.edu.hk/projects/CelebA.html )数据集包含超过20万名有注释的名人图片。 由于您要生成面孔,因此您不需要注释。 您可以通过更改“show_n_images”来查看第一个示例数。
show_n_images = 25
"""
DON'T MODIFY ANYTHING IN THIS CELL
"""
mnist_images = helper.get_batch(glob(os.path.join(data_dir, 'img_align_celeba/*.jpg'))[:show_n_images], 28, 28, 'RGB')
pyplot.imshow(helper.images_square_grid(mnist_images, 'RGB'))
由于该项目的主要重点是构建GAN,因此我们将为您处理数据。 MNIST和CelebA数据集的值将在28×28维度图像的-0.5至0.5的范围内。 CelebA图像将被裁剪以去除不包括脸部的图像部分,然后调整到28x28。
MNIST图像是具有单个[颜色通道](https://en.wikipedia.org/wiki/Channel_(digital_image%29) )的黑白图像,而CelebA图像具有[3色通道(RGB颜色通道)](https://en.wikipedia.org/wiki/Channel_(digital_image%29#RGB_Images)。 建立神经网络 您将通过实现以下功能构建构建GAN所需的组件:
model_inputsdiscriminatorgeneratormodel_lossmodel_opttrain这将检查以确保您具有正确版本的TensorFlow和访问GPU
"""
DON'T MODIFY ANYTHING IN THIS CELL
"""
from distutils.version import LooseVersion
import warnings
import tensorflow as tf
# Check TensorFlow Version
assert LooseVersion(tf.__version__) >= LooseVersion('1.0'), 'Please use TensorFlow version 1.0 or newer. You are using {}'.format(tf.__version__)
print('TensorFlow Version: {}'.format(tf.__version__))
# Check for a GPU
if not tf.test.gpu_device_name():
warnings.warn('No GPU found. Please use a GPU to train your neural network.')
else:
print('Default GPU Device: {}'.format(tf.test.gpu_device_name()))
实现model_inputs函数来创建神经网络的TF占位符。 应该创建以下占位符:
image_width, image_height, and image_channels.z_dim.在以下元组中返回占位符(实际输入图像的张量,z数据的张量)
import problem_unittests as tests
def model_inputs(image_width, image_height, image_channels, z_dim):
"""
创建模型输入
:param image_width:输入图像宽度
:param image_height:输入图像高度
:param image_channels:图像通道数
:param z_dim:Z的维数
:返回:元组(实数输入图像张量,z数据张量,学习率)
"""
real_input = tf.placeholder(tf.float32,shape=(None,image_width,image_height,image_channels))
z = tf.placeholder(tf.float32,shape=(None,z_dim))
learning_rate = tf.placeholder(tf.float32)
return real_input, z, learning_rate
"""
DON'T MODIFY ANYTHING IN THIS CELL THAT IS BELOW THIS LINE
"""
tests.test_model_inputs(model_inputs)
实现“鉴别器”来创建一个区分“图像”的鉴别器神经网络。 该函数应该能够重用神经网络中的变量。 使用范围名称为“discriminator”的tf.variable_scope来允许重用这些变量。 该函数应该返回一个元组(鉴别器的张量输出,鉴别器的张量逻辑)。
def discriminator(images, reuse=False):
"""
创建鉴别器网络
:参数图像:输入图像的张量
:param reuse:如果权重应重复使用,则为Boolean
:return:元组(鉴别器的张量输出,鉴别器的张量逻辑)
"""
alpha = 0.1
keep_prob = 0.5
with tf.variable_scope('discriminator',reuse=reuse):
'''
tf.nn.conv2d是TensorFlow里面实现卷积的函数,参考文档对它的介绍并不是很详细,实际上这是搭建卷积神经网络比较核心的一个方法,
非常重要
tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, name=None)
除去name参数用以指定该操作的name,与方法有关的一共五个参数:
第一个参数input:指需要做卷积的输入图像,它要求是一个Tensor,具有[batch, in_height, in_width, in_channels]这样的shape,
具体含义是[训练时一个batch的图片数量, 图片高度, 图片宽度, 图像通道数],注意这是一个4维的Tensor,
要求类型为float32和float64其中之一
第二个参数filter:相当于CNN中的卷积核,它要求是一个Tensor,具有[filter_height, filter_width, in_channels, out_channels]
这样的shape,具体含义是[卷积核的高度,卷积核的宽度,图像通道数,卷积核个数],要求类型与参数input相同,
有一个地方需要注意,第三维in_channels,就是参数input的第四维
第三个参数strides:卷积时在图像每一维的步长,这是一个一维的向量,长度4
第四个参数padding:string类型的量,只能是"SAME","VALID"其中之一,这个值决定了不同的卷积方式(后面会介绍)
第五个参数:use_cudnn_on_gpu:bool类型,是否使用cudnn加速,默认为true
tf.layer.conv2d和tf.nn.conv2d功能一样,只不过参数不一样。
'''
#第一层卷积,
conv1 = tf.layers.conv2d(images,64,5,strides=2,padding='same',kernel_initializer= tf.contrib.layers.xavier_initializer())
'''
tf.maximum:用法tf.maximum(a,b),返回的是a,b之间的最大值,
tf.miniimum:用法tf.miiinimum(a,b),返回的是a,b之间的最小值,
tf.argmax:用法tf.argmax(a,dimension),返回的是a中的某个维度最大值的索引,
tf.argmain:用法tf.argmin(a,dimension),返回的是a中的某个维度最小值的索引,
'''
conv1 = tf.maximum(conv1*alpha,conv1)
conv2 = tf.layers.conv2d(conv1,128,5,strides=2,padding='same', kernel_initializer= tf.contrib.layers.xavier_initializer())
'''
tensorflow中关于BN(Batch Normalization)的函数分别是:
tf.nn.moments
tf.nn.batch_normalization
tf.layers.batch_normalization
区别如下:http://www.jianshu.com/p/0312e04e4e83
'''
conv2 = tf.layers.batch_normalization(conv2,training=True)
conv2 = tf.maximum(conv2*alpha,conv2)
conv2 = tf.nn.dropout(conv2,keep_prob=keep_prob)
conv3 = tf.layers.conv2d(conv2,256,5,strides=2,padding='same',kernel_initializer= tf.contrib.layers.xavier_initializer())
conv3 = tf.layers.batch_normalization(conv3,trainable=True)
conv3 = tf.maximum(conv3*alpha,conv3)
conv3 = tf.nn.dropout(conv3,keep_prob=keep_prob)
flat = tf.reshape(conv3, (-1, 4*4*256))
logits = tf.layers.dense(flat, 1)
out = tf.sigmoid(logits)
return out, logits
"""
DON'T MODIFY ANYTHING IN THIS CELL THAT IS BELOW THIS LINE
"""
tests.test_discriminator(discriminator, tf)
实现generator来生成一个使用z的图像。 该函数应该能够重用神经网络中的变量。 使用范围名称为“generator”的tf.variable_scope来允许重用这些变量。 该函数应返回生成的28 x 28 xout_channel_dim图像。
def generator(z, out_channel_dim, is_train=True):
"""
创建生成器网络
:参数z:输入z
:param out_channel_dim:输出图像中的通道数
:param is_train:如果生成器用于训练,则为Boolean
:return: The tensor output of the generator
"""
alpha_temp =0.1
keep_prob = 0.5
with tf.variable_scope('generator',reuse= not is_train):
x = tf.layers.dense(z, 7*7*1024)
x = tf.reshape(x,(-1, 7, 7, 1024))
x = tf.layers.batch_normalization(x,training=is_train)
x = tf.maximum(x*alpha_temp,x)
conv1 = tf.layers.conv2d_transpose(x,512,5,strides=2,padding='same',kernel_initializer= tf.contrib.layers.xavier_initializer())
conv1 = tf.layers.batch_normalization(conv1,training=is_train)
conv1 = tf.maximum(conv1*alpha_temp,conv1)
conv1 = tf.nn.dropout(conv1,keep_prob=keep_prob)
conv2 = tf.layers.conv2d_transpose(conv1,256,5,strides=2,padding='same',kernel_initializer= tf.contrib.layers.xavier_initializer())
conv2 = tf.layers.batch_normalization(conv2,training=is_train)
conv2 = tf.maximum(conv2*alpha_temp,conv2)
conv2 = tf.nn.dropout(conv2,keep_prob=keep_prob)
logits = tf.layers.conv2d_transpose(conv2,out_channel_dim,5,strides=1,padding='same',kernel_initializer= tf.contrib.layers.xavier_initializer())
out = tf.tanh(logits)
return out
"""
DON'T MODIFY ANYTHING IN THIS CELL THAT IS BELOW THIS LINE
"""
tests.test_generator(generator, tf)
实施“model_loss”来构建GAN进行训练并计算损失。 该函数应该返回一个元组(鉴别器丢失,发生器丢失)。 使用您实现的以下功能:
discriminator(images,reuse = False)generator(z,out_channel_dim,is_train = True)def model_loss(input_real, input_z, out_channel_dim):
"""
得到鉴别器和发生器的损失
:param input_real:来自真实数据集的图像
:param input_z:Z输入
:param out_channel_dim:输出图像中的通道数
:return: A tuple of (discriminator loss, generator loss)
"""
smooth = 0.1
g_model = generator(input_z, out_channel_dim)
d_model_real, d_logits_real = discriminator(images = input_real)
d_model_fake, d_logits_fake = discriminator(images = g_model, reuse = True)
'''
tf.reduce_mean(input_tensor, reduction_indices=None, keep_dims=False, name=None)
计算张量的尺寸的元素平均值。
交叉熵(Cross Entropy)是Loss函数的一种(也称为损失函数或代价函数),用于描述模型预测值与真实值的差距大小,
常见的Loss函数就是均方平方差(Mean Squared Error)
TensorFlow针对分类问题,实现了四个交叉熵函数,分别是
tf.nn.sigmoid_cross_entropy_with_logits、
tf.nn.softmax_cross_entropy_with_logits、
tf.nn.sparse_softmax_cross_entropy_with_logits
tf.nn.weighted_cross_entropy_with_logits
sigmoid_cross_entropy_with_logits这个函数的输入是logits和targets,logits就是神经网络模型中的 W * X矩阵,注意不需要经过sigmoid,
而targets的shape和logits相同,
就是正确的label值,例如这个模型一次要判断100张图是否包含10种动物,这两个输入的shape都是[100, 10]。注释中还提到这10个分类之间是独立的、
不要求是互斥,这种问题我们成为多目标,例如判断图片中是否包含10种动物,label值可以包含多个1或0个1,还有一种问题是多分类问题,
例如我们对年龄特征分为5段,只允许5个值有且只有1个值为1,这种问题可以直接用这个函数吗?答案是不可以
'''
d_loss_real = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits = d_logits_real,
labels = tf.ones_like(d_model_real)*(1-smooth)))
d_loss_fake = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits = d_logits_fake,
labels = tf.zeros_like(d_model_fake)))
g_loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits = d_logits_fake,
labels = tf.ones_like(d_model_fake)))
d_loss = d_loss_real + d_loss_fake
return (d_loss, g_loss)
"""
DON'T MODIFY ANYTHING IN THIS CELL THAT IS BELOW THIS LINE
"""
tests.test_model_loss(model_loss)
实现model_opt来创建GAN的优化操作。 使用tf.trainable_variables获取所有可培训的变量。 用名称和标识符和生成器范围名称过滤变量。 该功能应该返回一个元组(鉴别器训练操作,发电机训练操作)。
def model_opt(d_loss, g_loss, learning_rate, beta1):
"""
获取优化操作
:param d_loss:Discriminator loss Tensor
:param g_loss:发生器损失张量
:param learning_rate:学习率占位符
:param beta1:优化器中第一时刻的指数衰减率
:return: A tuple of (discriminator training operation, generator training operation)
"""
t_vars = tf.trainable_variables()
d_vars = [var for var in t_vars if var.name.startswith('discriminator')]
g_vars = [var for var in t_vars if var.name.startswith('generator')]
# Optimize
'''
TensorFlow提供的tf.train.AdamOptimizer来控制学习速度。AdamOptimizer通过使用动量(参数的移动平均数)来改善传统梯度下降,
促进超参数动态调整。
'''
with tf.control_dependencies(tf.get_collection(tf.GraphKeys.UPDATE_OPS)):
d_train_opt = tf.train.AdamOptimizer(learning_rate, beta1 = beta1).minimize(d_loss, var_list = d_vars)
g_train_opt = tf.train.AdamOptimizer(learning_rate, beta1 =beta1).minimize(g_loss, var_list = g_vars)
return d_train_opt, g_train_opt
"""
DON'T MODIFY ANYTHING IN THIS CELL THAT IS BELOW THIS LINE
"""
tests.test_model_opt(model_opt, tf)
"""
DON'T MODIFY ANYTHING IN THIS CELL
"""
import numpy as np
def show_generator_output(sess, n_images, input_z, out_channel_dim, image_mode):
"""
Show example output for the generator
:param sess: TensorFlow session
:param n_images: Number of Images to display
:param input_z: Input Z Tensor
:param out_channel_dim: The number of channels in the output image
:param image_mode: The mode to use for images ("RGB" or "L")
"""
cmap = None if image_mode == 'RGB' else 'gray'
z_dim = input_z.get_shape().as_list()[-1]
example_z = np.random.uniform(-1, 1, size=[n_images, z_dim])
samples = sess.run(
generator(input_z, out_channel_dim, False),
feed_dict={input_z: example_z})
images_grid = helper.images_square_grid(samples, image_mode)
pyplot.imshow(images_grid, cmap=cmap)
pyplot.show()
实施“train”来建设和训练GAN。 使用您实现的以下功能:
model_inputs(image_width,image_height,image_channels,z_dim)model_loss(input_real,input_z,out_channel_dim)model_opt(d_loss,g_loss,learning_rate,beta1)在训练时使用show_generator_output显示generator输出。 为每个批次运行“show_generator_output”将大大增加培训时间并增加笔记本的大小。 建议每100批打印一次“发生器”输出。
def train(epoch_count, batch_size, z_dim, learning_rate, beta1, get_batches, data_shape, data_image_mode):
"""
训练GAN
:param epoch_count:历元数
:param batch_size:批量大小
:param z_dim:Z维
:param learning_rate:学习率
:param beta1:优化器中第一时刻的指数衰减率
:param get_batches:获取批次的功能
:param data_shape:数据的形状
:param data_image_mode:图像使用的图像模式(“RGB”或“L”)
"""
steps = 0
if (data_image_mode == "L"):
out_channel_dim = 1
else:
out_channel_dim = 3
print_every = 10
show_every = 100
samples, losses = [],[]
inputs_real, inputs_z, lr = model_inputs(data_shape[1],
data_shape[2],
data_shape[3],
z_dim)
lr = learning_rate
d_loss, g_loss = model_loss(inputs_real,
inputs_z,
out_channel_dim)
d_opt, g_opt = model_opt(d_loss, g_loss, lr, beta1)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
for epoch_i in range(epoch_count):
for batch_images in get_batches(batch_size):
steps += 1
batch_images = batch_images *2
batch_z = np.random.uniform(-1, 1, size=(batch_size, z_dim))
_ = sess.run(d_opt, feed_dict={inputs_real: batch_images,
inputs_z: batch_z})
_ = sess.run(g_opt, feed_dict={inputs_z: batch_z,
inputs_real: batch_images})
if steps % print_every == 0:
train_loss_d = d_loss.eval({inputs_z: batch_z, inputs_real: batch_images})
train_loss_g = g_loss.eval({inputs_z: batch_z})
print("Epoch {}/{}...".format((epoch_i+1), epoch_count),
"Discriminator Loss: {:.4f}".format(train_loss_d),
"Generator Loss: {:.4f}".format(train_loss_g))
#losses.append((train_loss_d,train_loss_g))
if steps % show_every == 0:
show_generator_output(sess, 9, inputs_z, data_shape[3],
data_image_mode)
在MNIST上测试您的GAN架构。 经过2个纪元,GAN应该能够生成看起来像手写数字的图像。 确保发电机的损耗低于鉴别器的损耗或接近0。
batch_size = 64
z_dim = 100
learning_rate = 0.0002
beta1 = 0.5
"""
DON'T MODIFY ANYTHING IN THIS CELL THAT IS BELOW THIS LINE
"""
epochs = 2
mnist_dataset = helper.Dataset('mnist', glob(os.path.join(data_dir, 'mnist/*.jpg')))
with tf.Graph().as_default():
train(epochs, batch_size, z_dim, learning_rate, beta1, mnist_dataset.get_batches,
mnist_dataset.shape, mnist_dataset.image_mode)
在CelebA上运行你的GAN。 平均GPU需要大约20分钟才能运行一个时代。 您可以运行整个时代,或者当它开始生成逼真的面孔时停止。
batch_size = 64
z_dim = 100
learning_rate = 0.0002
beta1 = 0.5
"""
DON'T MODIFY ANYTHING IN THIS CELL THAT IS BELOW THIS LINE
"""
epochs = 1
celeba_dataset = helper.Dataset('celeba', glob(os.path.join(data_dir, 'img_align_celeba/*.jpg')))
with tf.Graph().as_default():
train(epochs, batch_size, z_dim, learning_rate, beta1, celeba_dataset.get_batches,
celeba_dataset.shape, celeba_dataset.image_mode)
提交此项目时,请确保在保存笔记本计算机之前运行所有单元格。 将笔记本文件保存为“dlnd_face_generation.ipynb”,并将其另存为“File” - >“Download as”下的HTML文件。 在您的提交中包含“helper.py”和“problem_unittests.py”文件。